﻿//-----------------------------------------------------------------------
// <copyright file="ConsoleView.xaml.cs" author="Artak Mkrtchyan">
//     Creative Commons - GNU General Public License (http://creativecommons.org/licenses/GPL/2.0/
// </copyright>
// <author>Artak Mkrtchyan</author>
// <email>mkArtak@gmail.com</email>
// <date>15/07/2012</date>
//-----------------------------------------------------------------------

using ConsoleHoster.Common.UserInput;
using ConsoleHoster.ViewModel;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

namespace ConsoleHoster.View
{
	/// <summary>
	/// Interaction logic for ConsoleView.xaml
	/// </summary>
	public partial class ConsoleView : UserControl
	{
		public ConsoleView()
		{
			InitializeComponent();
		}

		private void Zoom(MouseWheelEventArgs e)
		{
			if (this.ViewModel.Zoom(e.Delta))
			{
				e.Handled = true;
			}
		}

		private void ScrollToEndOfContent()
		{
			try
			{
				this.mctHistory.ScrollToEnd();
			}
			catch
			{
			}
		}

		private void UserControl_DataContextChanged_1(object sender, DependencyPropertyChangedEventArgs e)
		{
			ConsoleViewModel tmpOldVM = e.OldValue as ConsoleViewModel;
			if (tmpOldVM != null)
			{
				tmpOldVM.SearchVM.FindNext -= OnSearchVM_FindNext;
				tmpOldVM.CommandExecuted -= OnViewModel_CommandExecuted;
				tmpOldVM.CommandRetrievedFromHistory -= OnViewModel_CommandRetrievedFromHistory;

				this.UnregisterKeyboardInputHandlers(tmpOldVM.KeyboardInputHandler);
			}

			ConsoleViewModel tmpNewVM = e.NewValue as ConsoleViewModel;
			if (tmpNewVM != null)
			{
				tmpNewVM.SearchVM.FindNext += OnSearchVM_FindNext;
				tmpNewVM.CommandExecuted += OnViewModel_CommandExecuted;
				tmpNewVM.CommandRetrievedFromHistory += OnViewModel_CommandRetrievedFromHistory;

				this.RegisterKeyboardInputHandlers(tmpNewVM);
			}

			this.TryFocusCommandArea();
		}

		private void TryFocusCommandArea()
		{
			this.Dispatcher.BeginInvoke(new Action(() =>
			{
				this.txtCommand.Focus();
			}));
		}

		private void RegisterKeyboardInputHandlers(ConsoleViewModel argViewModel)
		{
			IKeyboardInputHandler tmpHandler = argViewModel.KeyboardInputHandler;
			if (tmpHandler != null)
			{
				tmpHandler.RegisterHandler(Key.Enter, new[] { Key.LeftCtrl }, null, ksp =>
					{
						int tmpCaretIndex = this.txtCommand.CaretIndex;
						argViewModel.CurrentCommand = argViewModel.CurrentCommand.Insert(tmpCaretIndex, Environment.NewLine);
						this.txtCommand.CaretIndex = tmpCaretIndex + 2;
						return true;
					});
				tmpHandler.RegisterHandler(Key.Enter, new[] { Key.RightCtrl }, null, ksp =>
					{
						int tmpCaretIndex = this.txtCommand.CaretIndex;
						argViewModel.CurrentCommand = argViewModel.CurrentCommand.Insert(tmpCaretIndex, Environment.NewLine);
						this.txtCommand.CaretIndex = tmpCaretIndex + 2;
						return true;
					});
				tmpHandler.RegisterHandler(Key.Tab, null, null, ksp =>
					{
						if (String.IsNullOrEmpty(argViewModel.CurrentCommand))
						{
							argViewModel.CurrentCommand = "\t";
						}
						else
						{
							argViewModel.CurrentCommand = argViewModel.CurrentCommand.Insert(this.txtCommand.CaretIndex, "\t");
						}

						return true;
					});
				tmpHandler.RegisterHandler(Key.Escape, null, null, ksp =>
					{
						argViewModel.CurrentCommand = String.Empty;
						return true;
					});

				tmpHandler.RegisterHandler(Key.Down, null, null, ksp =>
					{
						if (!argViewModel.IsMultilineCommand)
						{
							argViewModel.RetrieveRecentCommand.Execute(true);
							return true;
						}
						return false;
					});
				tmpHandler.RegisterHandler(Key.Up, null, null, ksp =>
					{
						if (!argViewModel.IsMultilineCommand)
						{
							argViewModel.RetrieveRecentCommand.Execute(false);
							return true;
						}
						return false;
					});
				tmpHandler.RegisterHandler(Key.Enter, null, null, ksp =>
					{
						argViewModel.RunTypedCommandCommand.Execute(null);
						return true;
					});
			}
		}

		private void UnregisterKeyboardInputHandlers(IKeyboardInputHandler argHandler)
		{
			if (argHandler != null)
			{
				argHandler.UnregisterHandler(Key.Enter, new[] { Key.LeftCtrl }, null);
				argHandler.UnregisterHandler(Key.Enter, new[] { Key.RightCtrl }, null);
				argHandler.UnregisterHandler(Key.Tab, null, null);
				argHandler.UnregisterHandler(Key.Escape, null, null);
				argHandler.UnregisterHandler(Key.Down, null, null);
				argHandler.UnregisterHandler(Key.Up, null, null);
				argHandler.UnregisterHandler(Key.Enter, null, null);
			}
		}

		private void txtCommand_PreviewKeyDown(object sender, KeyEventArgs e)
		{
			if (this.ViewModel.HandleKeyboardInput(e.Key, null))
			{
				e.Handled = true;
			}
		}

		private void UserControl_SizeChanged_1(object sender, SizeChangedEventArgs e)
		{
			this.ScrollToEndOfContent();
		}

		private void OnViewModel_CommandExecuted(object sender, EventArgs e)
		{
			if (!this.Dispatcher.CheckAccess())
			{
				this.Dispatcher.Invoke(new Action(() =>
				{
					this.OnViewModel_CommandExecuted(sender, e);
				}));
				return;
			}

			this.txtCommand.Focus();
			this.txtCommand.SelectionStart = this.txtCommand.Text.Length;
		}

		private void OnViewModel_CommandRetrievedFromHistory(object sender, EventArgs e)
		{
			this.txtCommand.SelectionStart = this.txtCommand.Text.Length;
			this.ScrollToEndOfContent();
		}

		private void OnSearchVM_FindNext(string argTextToFind)
		{
			this.mctHistory.FindNext(argTextToFind);
		}

		private void mctHistory_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
		{
			this.Zoom(e);
		}

		private void txtCommand_TextChanged(object sender, TextChangedEventArgs e)
		{
			if (this.ViewModel != null && this.ViewModel.SuggestionProvided)
			{
				this.txtCommand.SelectionStart = this.txtCommand.Text.Length;
				this.ViewModel.SuggestionProvided = false;
			}
		}

		private void txtCommand_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
		{
			this.Zoom(e);
		}

		private void txbHistory_TextChanged(object sender, TextChangedEventArgs e)
		{
			if (this.ViewModel != null && this.ViewModel.AutoScroll)
			{
				(sender as TextBoxBase).ScrollToEnd();
			}
		}

		private ConsoleViewModel ViewModel
		{
			get
			{
				return this.DataContext as ConsoleViewModel;
			}
		}
	}
}